import express, { Response, Request, NextFunction } from 'express'

import https from 'https'
// import helmet from 'helmet'
import sharp from 'sharp'
import path from 'path'
import fs from 'fs'
import { getConfig, setConfig } from '@/utils/file'
import { ServerConfig, ConfigCallback, ImgReqQuery, ImgReqParams } from './types'

const app = express()
let server: null | ReturnType<typeof app.listen> = null // 服务实例，初始化为 null
let imagePath = '' // 图片存放目录

// 防止图片路径中包含 ..，防止路径穿越
app.use((req: Request, res: Response, next: NextFunction): void | Promise<void> => {
  if (req.path.includes('../')) {
    res.status(400).send('Invalid request path')
  } else {
    next()
  }
})
// 安全中间件
// app.use(helmet())
// 提供图片访问接口
app.get('/:alias/*', async (req: Request, res: Response): Promise<void> => {
  const { w: width = '', h: height = '', s: scale = '' } = req.query as ImgReqQuery
  const fileName = req.params?.[0]
  const { alias } = req.params as ImgReqParams
  if (!alias) {
    res.status(400).send('Alias is required')
    return
  }
  // 确保传入了图片名称
  if (!fileName) {
    res.status(400).send('File name is required')
    return
  }
  try {
    const regex = new RegExp(alias + '=(.*?)(?:[\\n|]|$)', 'mg') // 使用非贪婪匹配并考虑换行符
    const match = regex.exec(imagePath)
    const resImgPath = match?.[1]
    let image_path = ''
    if (resImgPath) {
      // 图片存放目录
      image_path = path.resolve(resImgPath.trim())
    } else {
      res.status(400).send('Alias not found')
      return
    }
    // 读取原始图片
    const filePath = path.join(image_path, fileName)
    // 检查文件是否存在
    if (!fs.existsSync(filePath)) {
      res.status(404).send('File not found')
      return
    }
    // 如果没有指定宽高，则返回原始图片
    if (!width && !height && !scale) return res.sendFile(filePath)
    // 开始处理图片
    const image = sharp(filePath)
    // 获取图片的原始尺寸
    const metadata: sharp.Metadata = await image.metadata()
    if (!metadata.width || !metadata.height) {
      res.status(400).send('Unable to determine image dimensions')
      return
    }
    let newWidth: number, newHeight: number
    // 如果传入了比例(scale)，根据比例计算新的尺寸
    if (scale) {
      const scaleFactor = parseFloat(scale)
      if (isNaN(scaleFactor) || scaleFactor <= 0 || scaleFactor > 1) {
        res.status(400).send('Invalid scale parameter')
        return
      }
      // 计算新的宽高
      newWidth = Math.round(metadata.width * scaleFactor)
      newHeight = Math.round(metadata.height * scaleFactor)
    } else {
      // 如果只提供height、width的其中一个，则按照另外一个参数进行缩放
      newWidth = parseInt(width, 10) || Math.round((+height / metadata.height) * metadata.width)
      newHeight = parseInt(height, 10) || Math.round((+width / metadata.width) * metadata.height)
    }
    const resizedImage: Buffer<ArrayBufferLike> = await image.resize(newWidth, newHeight).toBuffer()
    // 设置响应类型为图片
    res.type('image/jpeg')
    res.send(resizedImage)
  } catch (_error) {
    console.log(_error)
    // 处理错误，例如文件未找到
    res.status(500).send('Error processing the image\r\n')
  }
})
// 获取服务配置的方法
async function getServerConfig(callback?: ConfigCallback): Promise<ServerConfig> {
  const {
    start = false,
    port = 3000,
    img_path = '',
    is_https = false,
    https_key = '',
    https_cert = '',
    https_ca_cert = ''
  } = await getConfig('img-server')
  const config: ServerConfig = {
    start,
    port,
    img_path,
    is_https,
    https_key,
    https_cert,
    https_ca_cert
  }
  callback && callback(config)
  return config
}

// 封装返回对象的函数
export function createResponse(data: unknown, msg: string, code: number) {
  console.log(msg)
  return {
    data: data,
    msg: msg,
    code: code
  }
}

// 启动服务的方法
function startServer() {
  return new Promise((resolve, _reject) => {
    if (server) {
      return resolve(createResponse(null, '服务已经在运行', 200))
    }

    getServerConfig()
      .then(({ img_path, port, is_https, https_key, https_cert, https_ca_cert }) => {
        try {
          imagePath = img_path
          // HTTPS 选项
          if (is_https && https_key && https_cert) {
            const httpsOptions = {
              key: fs.readFileSync(path.resolve(https_key)),
              cert: fs.readFileSync(path.resolve(https_cert)),
              ...(https_ca_cert != '' ? { ca: fs.readFileSync(path.resolve(https_ca_cert)) } : {})
            }
            // 启动 HTTPS 服务
            server = https.createServer(httpsOptions, app).listen(port, () => {
              resolve(createResponse(null, 'HTTPS服务已启动', 200))
            })
          } else {
            // 启动 HTTP 服务
            server = app.listen(port, () => {
              resolve(createResponse(null, '服务已启动', 200))
            })
          }
        } catch (_error) {
          resolve(createResponse(null, '启动服务时发生错误', 500))
        }
      })
      .catch((_error) => {
        resolve(createResponse(null, '获取服务配置时发生错误', 500))
      })
  })
}

// 停止服务的方法
function stopServer() {
  return new Promise((resolve, _reject) => {
    if (!server) {
      return resolve(createResponse(null, '服务没有运行', 500))
    }

    try {
      server.close(() => {
        server = null
        resolve(createResponse(null, '服务已停止', 200))
      })
    } catch (_error) {
      resolve(createResponse(null, '停止服务时发生错误', 500))
    }
  })
}

function runStartServer() {
  getServerConfig((config) => {
    const { start = false } = config
    console.log('🚀🚀🚀 getServerStart', start)
    start == true &&
      startServer().then((res: unknown) => {
        const response = res as ReturnType<typeof createResponse>
        if (response.code != 200) {
          config.start = false
          setConfig(config, 'img-server')
          console.log('🚀🚀🚀 startServer', '服务启动失败')
        }
      })
  })
}

export { startServer, stopServer, getServerConfig, runStartServer }
